//--------------------------------------------------------------
//
// Qizhi Zhang 
// ezhung@gmail.com
// http://www.moorwind.com
//
//--------------------------------------------------------------
package reader.model
{
	import flash.data.EncryptedLocalStore;
	import flash.utils.ByteArray;
	
	import org.puremvc.as3.multicore.patterns.proxy.Proxy;
	
	import reader.ApplicationFacade;
	import reader.core.ReaderModelLocator;
	import reader.dao.IAccountDAO;
	import reader.model.vo.UserVO;
	import reader.utils.CryptoUtil;

	public class UserProxy extends Proxy implements IUserProxy
	{
		////////////////////////////////////////////////////////////////////////////////
		//public properties
		
		public static const NAME:String = "UserProxy";
		
		////////////////////////////////////////////////////////////////////////////////
		//private variables
		private const USER_SECRET		:String = "d6a58ea19ecf63bd29d3e4fa4c737ffb";
		private const MAX_LOGIN_INTERNAL:uint = 180000;
		
		private var loginAble:Boolean = true;
		private var retryMax:uint = 10;
				
		private var accountDAO:IAccountDAO;
		private var readerModelLocator:ReaderModelLocator = ReaderModelLocator.instance;
		
		//////////////////////////////////////////////////////////////////////////////
		//constructor
		public function UserProxy()
		{
			super(NAME, []);
			accountDAO = readerModelLocator.sqliteDAOFactory.accountDAO;
		}
		
		////////////////////////////////////////////////////////////////////////////////
		//methods
		
		public function validate(username:String, password:String):void
		{
			//if locked, try to get remain date.
			var lockByte:ByteArray = EncryptedLocalStore.getItem(username);
			var ctime:uint = new Date().getTime();
			var lockedInterval:uint;
			if(lockByte)
			{
				lockByte.position = 0;
				var lockTime:uint= lockByte.readUnsignedInt();
				lockedInterval = ctime - lockTime;
				if(lockedInterval >= MAX_LOGIN_INTERNAL)
				{
					loginAble = true;
					EncryptedLocalStore.removeItem(username);
				}
				else
				{
					loginAble = false;
				} 
				
			}
			if(!loginAble)
			{
				sendNotification(ApplicationFacade.LOGIN_UNABLE, lockedInterval);
				return;
			}
			
			//validate user name and password.
			var user:UserVO = accountDAO.selectUserByName(username);
			var isCorrect:Boolean;
			if(user && user.userName == username)
			{
				var passwordByte:ByteArray = EncryptedLocalStore.getItem(CryptoUtil.encrypt(user.userName, USER_SECRET));
				if(passwordByte)
				{
					//if user has a password
					var encryptedPassword:String = passwordByte.readUTFBytes(passwordByte.length);
					var decryptedPassword:String = CryptoUtil.decrypt(encryptedPassword, USER_SECRET);
					isCorrect = (password == decryptedPassword);
				}
				else
				{
					//else if user's password is empty
					var decryptedNeeded:String = CryptoUtil.decrypt(user.password, USER_SECRET);
					var needPassword:Array = decryptedNeeded.split("@");
					if(needPassword && needPassword.length > 1 && needPassword[0] == user.userName && needPassword[1] == "false")
					{
						isCorrect = true
					}
				}
			}
			
			//if incorrent passwords and tried 10 times login, lock the user.
			if(isCorrect)
			{
				readerModelLocator.user = user;
				sendNotification(ApplicationFacade.LOGIN_SUCCESS, readerModelLocator.airReader);
			}
			else
			{
				retryMax --;
				if(retryMax <= 0)
				{
					retryMax = 0;
					var interval:ByteArray = new ByteArray();
					interval.writeUnsignedInt(ctime);
					EncryptedLocalStore.setItem(username, interval);
					sendNotification(ApplicationFacade.LOGIN_UNABLE, MAX_LOGIN_INTERNAL);
					return;
				} 
				sendNotification(ApplicationFacade.LOGIN_FAIL, retryMax);
			}
		}
		
		public function register(user:UserVO):void
		{
			var parparePassword:String;
			if(!user.password || user.password == "" )
			{
				parparePassword = user.userName + "@false";
			}
			else
			{
				parparePassword = user.userName + "@true";
			}
			var encryptedPassword:String = user.password;
			user.password = CryptoUtil.encrypt(parparePassword, USER_SECRET);
			var uid:int = accountDAO.insertUser(user);
			if( uid > 0)
			{
				user.userId = uid;
				updatePassword(user.userName, encryptedPassword, "", true);
				readerModelLocator.user = user;
				sendNotification(ApplicationFacade.REGISTER_COMPLETE, user);
			}
			else
			{
				sendNotification(ApplicationFacade.REGISTER_COMPLETE, null);
			}
		}
		
		public function updatePassword(username:String, password:String, oldpassword:String = "", isRegister:Boolean = false):void
		{
			var parparePassword:String;
			var passwordByte:ByteArray = new ByteArray();
			var itemKey:String = CryptoUtil.encrypt(username, USER_SECRET);
			var encryptedPassword:String = CryptoUtil.encrypt(password, USER_SECRET);
			if(oldpassword == "" && password != "")
			{
				parparePassword = username + "@true";
				if(!isRegister)
				{
					//if it is a registered user wanna add password, we need to change dataset.
					readerModelLocator.user.password = CryptoUtil.encrypt(parparePassword, USER_SECRET);
					if(accountDAO.updatePassword(readerModelLocator.user))
					{
						passwordByte.writeUTFBytes(encryptedPassword);
						EncryptedLocalStore.setItem(itemKey, passwordByte);
						sendNotification(ApplicationFacade.SETTING_PASSWORD);
						return;
					}
				}
				passwordByte.writeUTFBytes(encryptedPassword);
				EncryptedLocalStore.setItem(itemKey, passwordByte);
				return;
			}
			else if(oldpassword != "" && password == "")
			{
				parparePassword = username + "@false";
				//user had registered, change dataset and removed password form EncryptedLocalStore.
				readerModelLocator.user.password = CryptoUtil.encrypt(parparePassword, USER_SECRET);
				if(accountDAO.updatePassword(readerModelLocator.user))
				{
					EncryptedLocalStore.removeItem(itemKey);
					sendNotification(ApplicationFacade.SETTING_PASSWORD);
				}
			}
			else if(oldpassword != "" && password != "")
			{
				//user had registered, change password form EncryptedLocalStore.
				passwordByte.writeUTFBytes(encryptedPassword);
				EncryptedLocalStore.setItem(itemKey, passwordByte);
				sendNotification(ApplicationFacade.SETTING_PASSWORD);
			}
			
		}
		
		public function checkUserNameExit(username:String):void
		{
			if(accountDAO.getCount(username) > 0)
			{
				sendNotification(ApplicationFacade.REGISTER_USER_EXIT);
			}
		}
		
		public function updateUserSetting(user:UserVO):void
		{
			if(accountDAO.updateUser(user))
			{
				sendNotification(ApplicationFacade.SETTING_UPDATE);
			}
		}
		
		public function updateUserIsDisplayOldLabels(user:UserVO):void
		{
			if(!accountDAO.updateShowLabelType(user))
			{
				sendNotification(ApplicationFacade.DATA_ERROR, "error");
			}
			else
			{
				sendNotification(ApplicationFacade.CREATE_LABEL_TREE);
			}
		}
		
		public function updateUserGetBlogType(user:UserVO):void
		{
			if(!accountDAO.updateGetBlogType(user))
			{
				sendNotification(ApplicationFacade.DATA_ERROR, "error");
			}
		}
		
		public function updateAutoSaveType(user:UserVO):void
		{
			if(!accountDAO.updateAutoSaveType(user))
			{
				sendNotification(ApplicationFacade.DATA_ERROR, "error");
			}
		}
		
		public function deleteAccount():void
		{
			accountDAO.deleteUser(readerModelLocator.user);
		}
		
		////////////////////////////////////////////////////////////////////////////////
		//events
		
	}
}